﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharedUtils;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Engine
{
    class GraphBuilder
    {
        public static Graph<Node, EdgeData> buildGraph()
        {
            List<Entity> entities = new List<Entity>();
            entities.Add(new PictureEntity("Picture1", new Vector2(0, 0), "images/AddNode", new Vector2(2, 1)));
            entities.Add(new PictureEntity("Picture2", new Vector2(100, 100), "images/AddNode", new Vector2(1, 1)));
            entities.Add(new PictureEntity("Picture3", new Vector2(1200, 600), "images/ColorNode", new Vector2(1, 1)));
            entities.Add(new PictureEntity("Picture4", new Vector2(0, 600), "images/LightNode", new Vector2(1, 1)));
            entities.Add(new PictureEntity("Picture5", new Vector2(1200, 0), "images/SubNode", new Vector2(1, 1)));            
            entities.Add(new SoundEntity("SoundEnt1", new Vector2(600,300), "images/Play", "images/Pause", "images/Stop", new Vector2(1,1),"sounds/explosionM"));

            Camera2d defaultCamera = new Camera2d("default_Camera");
            defaultCamera._pos = new Vector2(0, 0);
            defaultCamera.Zoom = 1f;

            Camera2d cam1 = new Camera2d("Camera1");
            cam1._pos = new Vector2(0, 0);
            cam1.Zoom = 3f;

            Camera2d cam2 = new Camera2d("Camera2");
            cam2._pos = new Vector2(1100, 500);
            cam2.Zoom = 3f;

            Camera2d cam3 = new Camera2d("Camera3");
            cam3._pos = new Vector2(1100, 0);
            cam3.Zoom = 3f;

            Camera2d cam4 = new Camera2d("Camera4");
            cam4._pos = new Vector2(0, 0);
            cam4.Zoom = 0.5f;

            Camera2d cam5 = new Camera2d("Camera5");
            cam5._pos = new Vector2(0, 500);
            cam5.Zoom = 3f;


            Graph<Node, EdgeData> g = new Graph<Node, EdgeData>(true, true);

            Node n1 = new Node("Node1");
            n1.entities = entities;
            n1.camera = defaultCamera;

            List<Entity> entities2 = GraphBuilder.CopyEntities(entities);
            Node n2 = new Node("Node2");
            n2.entities = entities2;
            n2.camera = cam1;

            List<Entity> entities3 = GraphBuilder.CopyEntities(entities);
            Node n3 = new Node("Node3");
            n3.entities = entities3;
            n3.camera = cam2;

            List<Entity> entities4 = GraphBuilder.CopyEntities(entities);
            Node n4 = new Node("Node4");
            n4.entities = entities4;
            n4.camera = cam3;

            List<Entity> entities5 = GraphBuilder.CopyEntities(entities);
            Node n5 = new Node("Node5");
            n5.entities = entities5;
            n5.camera = cam4;
            n5.entities[0].isVisible = false; n5.entities[2].isVisible = false;
            n5.entities[3].isVisible = false; n5.entities[4].isVisible = false;

            List<Entity> entities6 = GraphBuilder.CopyEntities(entities);
            Node n6 = new Node("Node6");
            n6.entities = entities6;
            n6.camera = cam5;

            List<Entity> entities7 = GraphBuilder.CopyEntities(entities);
            Node n7 = new Node("Node7");
            n7.entities = entities7;
            n7.camera = defaultCamera;
            ((SoundEntity)n7.entities[5]).state = SoundEntity.SoundEntityState.PLAYING;

            List<Entity> entities8 = GraphBuilder.CopyEntities(entities);
            Node n8 = new Node("Node8");
            n8.entities = entities8;
            n8.camera = defaultCamera;
            ((SoundEntity)n8.entities[5]).state = SoundEntity.SoundEntityState.PAUSED;


            g.Add(n1);
            g.Add(n2);
            g.Add(n3);
            g.Add(n4);
            g.Add(n5);
            g.Add(n6);
            g.Add(n7);
            g.Add(n8);

            EdgeData ed1 = new EdgeData();
            ed1.ent = n1.entities[0];
            ed1.inputTypes.Add(new InputType(InputType.InputName.Tap));
            ed1.cameraType = Interpolation.InterpolationMode.BOUNCE_EASEOUT;
            Edge<Node, EdgeData> e1 = new Edge<Node, EdgeData>(n1, n2, ed1);

            EdgeData ed2 = new EdgeData();
            ed2.ent = n2.entities[0];
            ed2.inputTypes.Add(new InputType(InputType.InputName.Tap));
            ed2.cameraType = Interpolation.InterpolationMode.BOUNCE_EASEOUT;
            Edge<Node, EdgeData> e2 = new Edge<Node, EdgeData>(n2, n1, ed2);

            EdgeData ed3 = new EdgeData();
            ed3.ent = n1.entities[0];
            ed3.inputTypes.Add(new InputType(InputType.InputName.Hold));
            ed3.cameraType = Interpolation.InterpolationMode.CUBIC_EASEIN;
            Edge<Node, EdgeData> e3 = new Edge<Node, EdgeData>(n1, n3, ed3);

            EdgeData ed4 = new EdgeData();
            ed4.ent = n3.entities[2];
            ed4.inputTypes.Add(new InputType(InputType.InputName.Tap));
            ed4.cameraType = Interpolation.InterpolationMode.CUBIC_EASEIN;
            Edge<Node, EdgeData> e4 = new Edge<Node, EdgeData>(n3, n1, ed4);

            EdgeData ed5 = new EdgeData();
            ed5.ent = n1.entities[0];
            ed5.inputTypes.Add(new InputType(InputType.InputName.DoubleTap));
            ed5.cameraType = Interpolation.InterpolationMode.ELASTIC_EASEOUT;
            Edge<Node, EdgeData> e5 = new Edge<Node, EdgeData>(n1, n4, ed5);

            EdgeData ed6 = new EdgeData();
            ed6.ent = n4.entities[4];
            ed6.inputTypes.Add(new InputType(InputType.InputName.Tap));
            ed6.cameraType = Interpolation.InterpolationMode.ELASTIC_EASEOUT;
            Edge<Node, EdgeData> e6 = new Edge<Node, EdgeData>(n4, n1, ed6);

            EdgeData ed7 = new EdgeData();
            ed7.ent = n1.entities[1];
            ed7.inputTypes.Add(new InputType(InputType.InputName.Tap));
            ed7.cameraType = Interpolation.InterpolationMode.SIGMOID;
            Edge<Node, EdgeData> e7 = new Edge<Node, EdgeData>(n1, n5, ed7);

            EdgeData ed8 = new EdgeData();
            ed8.ent = n5.entities[1];
            ed8.inputTypes.Add(new InputType(InputType.InputName.Tap));
            ed8.cameraType = Interpolation.InterpolationMode.SIGMOID;
            Edge<Node, EdgeData> e8 = new Edge<Node, EdgeData>(n5, n1, ed8);

            EdgeData ed9 = new EdgeData();
            ed9.ent = n1.entities[0];
            ed9.inputTypes.Add(new InputType(InputType.InputName.Timed, 10.0f));
            ed9.cameraType = Interpolation.InterpolationMode.SINE_EASEIN;
            Edge<Node, EdgeData> e9 = new Edge<Node, EdgeData>(n1, n6, ed9);

            EdgeData ed10 = new EdgeData();
            ed10.ent = n6.entities[1];
            ed10.inputTypes.Add(new InputType(InputType.InputName.Timed, 5.0f));
            ed10.cameraType = Interpolation.InterpolationMode.SINE_EASEOUT;
            Edge<Node, EdgeData> e10 = new Edge<Node, EdgeData>(n6, n1, ed10);

            EdgeData ed11 = new EdgeData();
            ed11.ent = n1.entities[5];
            ed11.inputTypes.Add(new InputType(InputType.InputName.Tap));
            Edge<Node, EdgeData> e11 = new Edge<Node, EdgeData>(n1, n7, ed11);

            EdgeData ed12 = new EdgeData();
            ed12.ent = n7.entities[5];
            ed12.inputTypes.Add(new InputType(InputType.InputName.DoubleTap));
            Edge<Node, EdgeData> e12 = new Edge<Node, EdgeData>(n7, n1, ed12);

            EdgeData ed13 = new EdgeData();
            ed13.ent = n7.entities[5];
            ed13.inputTypes.Add(new InputType(InputType.InputName.Tap));
            Edge<Node, EdgeData> e13 = new Edge<Node, EdgeData>(n7, n8, ed13);

            EdgeData ed14 = new EdgeData();
            ed14.ent = n8.entities[5];
            ed14.inputTypes.Add(new InputType(InputType.InputName.Tap));
            Edge<Node, EdgeData> e14 = new Edge<Node, EdgeData>(n8, n7, ed14);

            EdgeData ed15 = new EdgeData();
            ed15.ent = n1.entities[5];
            ed15.inputTypes.Add(new InputType(InputType.InputName.Tap));
            Edge<Node, EdgeData> e15 = new Edge<Node, EdgeData>(n8, n1, ed15);

            g.AddEdge(e1);
            g.AddEdge(e2);
            g.AddEdge(e3);
            g.AddEdge(e4);
            g.AddEdge(e5);
            g.AddEdge(e6);
            g.AddEdge(e7);
            g.AddEdge(e8);
            g.AddEdge(e9);
            g.AddEdge(e10);
            g.AddEdge(e11);
            g.AddEdge(e12);
            g.AddEdge(e13);
            g.AddEdge(e14);
            g.AddEdge(e15);

            return g;
        }

        public static Graph<Node, EdgeData> buildGraph2()
        {
            // GRAPH we will return
            Graph<Node, EdgeData> g = new Graph<Node, EdgeData>(true, true);

            // ADD CAMERAS
            Camera2d defaultCamera = new Camera2d("default_camera");
            defaultCamera._pos = new Vector2(0, 0);
            defaultCamera.Zoom = 0.5f;

            // ADD the pictures we will need
            List<Entity> entities = new List<Entity>();

            entities.Add(new PictureEntity("Title", new Vector2(375, 150), "images/title", new Vector2(2, 1)));
            ((PictureEntity)entities[0]).pictureSize *= 1.5f;
            entities.Add(new PictureEntity("Center_Picture", new Vector2(975, 400), "images/test", new Vector2(1, 1)));
            ((PictureEntity)entities[1]).pictureSize *= 1.5f;
            for (int i = 0; i < 7; i++)
            {
                entities.Add(new PictureEntity("circle" + i, new Vector2(0, 0), "images/" + "circle" + i, new Vector2(1, 1)));
            }
            entities[2].position = new Vector2(400, 300);
            entities[8].position = new Vector2(2000, 325);
            ((PictureEntity)entities[2]).pictureSize *= 0.75f;
            ((PictureEntity)entities[8]).pictureSize *= 0.75f;

            entities[3].position = new Vector2(300, 650);
            entities[7].position = new Vector2(2025, 675);

            entities[4].position = new Vector2(600, 950);
            entities[6].position = new Vector2(1650, 950);
            ((PictureEntity)entities[4]).pictureSize *= 1.15f;
            ((PictureEntity)entities[6]).pictureSize *= 1.15f;

            entities[5].position = new Vector2(1100, 1050);
            ((PictureEntity)entities[5]).pictureSize *= 1.25f;


            Node root = new Node("Root");
            root.camera = defaultCamera;
            root.entities = CopyEntities(entities);
            g.Add(root);

            Camera2d[] cameras = new Camera2d[9];
            cameras[0] = defaultCamera;
            

            for (int i = 0; i < 8; i++)
            {
                cameras[i+1] = new Camera2d("Camera" + (i+1));
                Node n = new Node("Node" + (i + 1));
                n.camera = cameras[i+1];
                n.entities = CopyEntities(entities);
                g.Add(n);
            }

            // ADD ALL EDGES
            for (int i = 0; i < 8; i++)
            {
                EdgeData data = new EdgeData();
                data.inputTypes.Add(new InputType(InputType.InputName.Tap));
                data.cameraType = Interpolation.InterpolationMode.SIGMOID;
                data.ent = g.Nodes[0].entities[i + 1];

                EdgeData data2 = new EdgeData();
                data2.inputTypes.Add(new InputType(InputType.InputName.Tap));
                if (i == 7) data2.inputTypes.Add(new InputType(InputType.InputName.DoubleTap));
                data2.cameraType = Interpolation.InterpolationMode.SIGMOID;
                data2.ent = g.Nodes[i+1].entities[i + 1];

                EdgeData data3 = new EdgeData();
                data3.inputTypes.Add(new InputType(InputType.InputName.DoubleTap));
                data3.cameraType = Interpolation.InterpolationMode.SIGMOID;
                data3.ent = g.Nodes[i + 1].entities[i + 1];

                Edge<Node, EdgeData> e = new Edge<Node, EdgeData>(root, g.Nodes[i + 1], data);
                Edge<Node, EdgeData> e2 = new Edge<Node, EdgeData>(g.Nodes[i + 1], root, data2);

                Edge<Node, EdgeData> e3;
                if (i + 2 <= 8)
                {
                    e3 = new Edge<Node, EdgeData>(g.Nodes[i + 1], g.Nodes[i + 2], data3);
                    g.AddEdge(e3);
                }
                

                g.AddEdge(e);
                g.AddEdge(e2);
            }

            cameras[1].Zoom = 1.25f;
            cameras[1].Pos = entities[1].position - new Vector2(150, 100);

            cameras[2].Zoom = 2f;
            cameras[2].Pos = entities[2].position - new Vector2(200, 50);
            cameras[8].Zoom = 2f;
            cameras[8].Pos = entities[8].position - new Vector2(200, 50);

            cameras[3].Zoom = 2f;
            cameras[3].Pos = entities[3].position - new Vector2(100, 0);
            cameras[7].Zoom = 2f;                   
            cameras[7].Pos = entities[7].position - new Vector2(100, 0);

            cameras[4].Zoom = 1.7f;
            cameras[4].Pos = entities[4].position - new Vector2(120, 0);
            cameras[6].Zoom = 1.7f;
            cameras[6].Pos = entities[6].position - new Vector2(120, 0);

            cameras[5].Zoom = 1.55f;
            cameras[5].Pos = entities[5].position - new Vector2(150, 0);

            
            

            return g;
        }

        // Makes a copy of an entity list
        public static List<Entity> CopyEntities(List<Entity> entities)
        {
            List<Entity> answer = new List<Entity>();
            for (int i = 0; i < entities.Count; i++)
            {
                // Make a copy of that entity
                if (entities[i] is SoundEntity)
                    answer.Add(new SoundEntity((SoundEntity)entities[i]));
                else if (entities[i] is PictureEntity)
                    answer.Add(new PictureEntity((PictureEntity)entities[i]));
                else answer.Add(new Entity(entities[i]));
            }

            return answer;
        }
    }
}